﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BSCMFF.Core.DataAccessLayer;
using System.Collections;

namespace BSCMFF.Core.BusinessLayer
{
    /// <summary>
    /// Class for managing BSCTreeList items. 
    /// </summary>
    /// <remarks></remarks>
    public class BSCTreeListManager
    {
        /// <summary>
        /// Gets the data by date.
        /// </summary>
        /// <param name="date">The date.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public static List<BSCTreeListItem> GetDataByDate(DateTime date)
        {
            List<BSCTreeListItem> list = new List<BSCTreeListItem>();

            BSCEntities context = new BSCEntities();

            AddKPIs(date, list, context);

            AddPerspectives(list, context);

            // -- add Main TreeListItem

            BSCTreeListItem bli = new BSCTreeListItem();
            bli.ID = "0";
            bli.Name = "Balanced Scorecard";
            bli.ItemType = "bsc";

            Hashtable calculatedValues = CalculateValuesForBSC(list);

            bli.Progress = calculatedValues["progress"].ToString();
            bli.Performance = calculatedValues["performance"].ToString();
            bli.Start = calculatedValues["start"].ToString();
            bli.Current = calculatedValues["current"].ToString();
            bli.Target = calculatedValues["target"].ToString();
            bli.Min = "0";
            bli.Max = "100";


            //list.Add(new BSCTreeListItem(0, "Balanced Scorecard", "bsc", 0, 0));
            list.Add(bli);
            return list;
        }

        /// <summary>
        /// Calculates the values for BSCTreeList item.
        /// </summary>
        /// <param name="list">The list.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        private static Hashtable CalculateValuesForBSC(List<BSCTreeListItem> list)
        {
            int weights = 0;
            double progress = 0;
            double performance = 0;
            double start = 0;
            double target = 0;
            double current = 0;

            foreach (BSCTreeListItem l in list)
            {
                //if (l.ParentID != "0")
                if(l.ItemType == "KPI")
                {
                    weights += Convert.ToInt32(l.Weight);
                    progress += Convert.ToDouble(l.Progress) * Convert.ToInt32(l.Weight);
                    performance += Convert.ToDouble(l.Performance) * Convert.ToInt32(l.Weight);
                    start += Convert.ToDouble(l.Start) * Convert.ToInt32(l.Weight);
                    target += Convert.ToDouble(l.Target) * Convert.ToInt32(l.Weight);
                    current += Convert.ToDouble(l.Current) * Convert.ToInt32(l.Weight);
                }
            }

            Hashtable ht = new Hashtable();
            if (weights == 0)
            {
                ht["progress"] = "0";
                ht["performance"] = "0";
                ht["start"] = "0";
                ht["target"] = "0"; 
                ht["current"] = "0";
            }
            else
            {
                ht["progress"] = Convert.ToDecimal(progress / weights).ToString("#0.00");
                ht["performance"] = Convert.ToDecimal(performance / weights).ToString("#0.00");
                ht["start"] = Convert.ToDecimal(start / weights).ToString("#0.00");
                ht["target"] = Convert.ToDecimal(target / weights).ToString("#0.00");
                ht["current"] = Convert.ToDecimal(current / weights).ToString("#0.00");
            }
            return ht;
        }

        /// <summary>
        /// Adds the perspectives.
        /// </summary>
        /// <param name="list">The list.</param>
        /// <param name="context">The context.</param>
        /// <remarks></remarks>
        private static void AddPerspectives(List<BSCTreeListItem> list, BSCEntities context)
        {
            /// -- add perspectives
            List<Perspective> persps = new List<Perspective>();
            persps = (from k in context.Perspectives
                      select k).ToList();

            foreach (Perspective p in persps)
            {
                BSCTreeListItem bli = new BSCTreeListItem();
                bli.ID = "perspective" + p.Perspective_ID.ToString();
                bli.OrigID = p.Perspective_ID;
                bli.Name = p.Name;
                bli.ItemType = "Perspective";
                bli.ParentID = "0"; //root - BSC
                // "perspective" + p.Perspective_ID.ToString();
                //bli.Weight = p.Weight.ToString();

                //bli.Progress = CalculateProgressForPerspective(bli.ID, list); //kp.Progress.ToString();

                Hashtable calculatedValues = CalculateValuesForPerspective(bli.ID, list);

                bli.Progress = calculatedValues["progress"].ToString();
                bli.Performance = calculatedValues["performance"].ToString();
                bli.Start = calculatedValues["start"].ToString();
                bli.Current = calculatedValues["current"].ToString();
                bli.Target = calculatedValues["target"].ToString();
                bli.Min = "0";
                bli.Max = "100";
                //bli.Performance = kp.Performance.ToString();

                list.Add(bli);
            }
        }



        /// <summary>
        /// Adds the KPIs.
        /// </summary>
        /// <param name="date">The date.</param>
        /// <param name="list">The list of BSCTreeList item of type KPI.</param>
        /// <param name="context">The context.</param>
        /// <remarks></remarks>
        private static void AddKPIs(DateTime date, List<BSCTreeListItem> list, BSCEntities context)
        {
            var kpis = (from k in context.KPIs
                        where k.DateCreated <= date
                        select k).ToList();

            //List<KPI> kpiss = (from k in context.KPIs.in

            foreach (KPI k in kpis)
            {
                if (date == DateTime.Today) //values are in KPI
                {
                    BSCTreeListItem bli = new BSCTreeListItem();
                    bli.ID = k.KPI_ID.ToString();
                    bli.OrigID = k.KPI_ID;
                    bli.Name = k.Name;
                    bli.Description = k.Description;
                    bli.ItemType = "KPI";
                    bli.ParentID = "perspective" + k.Perspective_FK.ToString();

                    bli.Weight = k.Weight.ToString();
                    bli.Progress = k.Progress.ToString("#0.00");
                    bli.Performance = k.Performance.ToString("#0.00");
                    // bli.Progress = kp.Progress.ToString();

                    bli.Start = k.Start_Value.ToString();
                    bli.Current = k.Current_Value.ToString();
                    bli.Target = k.Target_Value.ToString();
                    bli.Min = k.Min.ToString();
                    bli.Max = k.Max.ToString();


                    list.Add(bli);
                }
                else // values are archived in KPI_Progress
                {
                    KPI_Progress kp;// = new KPI_Progress();


                    kp = (from progress in context.KPI_Progress
                          where progress.KPI_FK == k.KPI_ID && progress.Date == date //progress is archived every day automatically
                          select progress).SingleOrDefault();
                    //}

                    BSCTreeListItem bli = new BSCTreeListItem();
                    bli.ID = k.KPI_ID.ToString();
                    bli.OrigID = k.KPI_ID;
                    bli.Name = k.Name;
                    bli.Description = k.Description;
                    bli.ItemType = "KPI";
                    bli.ParentID = "perspective" + k.Perspective_FK.ToString();
                    if (kp != null)
                    {
                        bli.Weight = kp.Weight.ToString();
                        bli.Progress = kp.Progress.ToString("#0.00");
                        bli.Performance = kp.Performance.ToString("#0.00");
                        // bli.Progress = kp.Progress.ToString();

                        bli.Start = kp.Start_Value.ToString();
                        bli.Current = kp.Current_Value.ToString();
                        bli.Target = kp.Target_Value.ToString();
                        bli.Min = kp.Min.ToString();
                        bli.Max = kp.Max.ToString();
                    }

                    list.Add(bli);
                }

            }
        }

        /// <summary>
        /// Calculates the progress for perspective.
        /// </summary>
        /// <param name="p">The parent id of KPIs = ID of perspective.</param>
        /// <param name="list">The list.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        private static string CalculateProgressForPerspective(string p, List<BSCTreeListItem> list)
        {
            int weights = 0;
            double progress = 0;

            foreach (BSCTreeListItem l in list)
            {
                if (l.ParentID == p)
                {
                    weights += Convert.ToInt32(l.Weight);
                    progress += Convert.ToDouble(l.Progress) * Convert.ToInt32(l.Weight);
                }
            }

            return weights == 0 ? "0" : Convert.ToDecimal(progress / weights).ToString("#0.00");
        }

        /// <summary>
        /// Calculates the values for perspective.
        /// </summary>
        /// <param name="p">The p.</param>
        /// <param name="list">The list.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        private static Hashtable CalculateValuesForPerspective(string p, List<BSCTreeListItem> list)
        {
            int weights = 0;
            double progress = 0;
            double performance = 0;
            double start = 0;
            double target = 0;
            double current = 0;

            foreach (BSCTreeListItem l in list)
            {
                if (l.ParentID == p)
                {
                    weights += Convert.ToInt32(l.Weight);
                    progress += Convert.ToDouble(l.Progress) * Convert.ToInt32(l.Weight);
                    performance += Convert.ToDouble(l.Performance) * Convert.ToInt32(l.Weight);
                    start += Convert.ToDouble(l.Start) * Convert.ToInt32(l.Weight);
                    target += Convert.ToDouble(l.Target) * Convert.ToInt32(l.Weight);
                    current += Convert.ToDouble(l.Current) * Convert.ToInt32(l.Weight);
                }
            }

            Hashtable ht = new Hashtable();
            if(weights == 0)
            {
                ht["progress"] = "0";
                ht["performance"] = "0";
                ht["start"] = "0";
                ht["target"] = "0";
                ht["current"] = "0";
            }
            else
            {                
                ht["progress"] = Convert.ToDecimal(progress / weights).ToString("#0.00");
                ht["performance"] = Convert.ToDecimal(performance / weights).ToString("#0.00");
                ht["start"] = Convert.ToDecimal(start / weights).ToString("#0.00");
                ht["target"] = Convert.ToDecimal(target / weights).ToString("#0.00");
                ht["current"] = Convert.ToDecimal(current / weights).ToString("#0.00");
            }
            return ht;
        }
    }
}
